from tkinter import Frame,BROWSE,Label,Button,StringVar,messagebox,Listbox,ttk
import os,xlwt,configparser
from datetime import datetime,timedelta,date
from myFunction import mySftp,DBHelper,myconfig
from myXlsStyles import styleCommon,styleSpec
 
class fileParsing():
   def __init__(self):
       self.frame = Frame(width=550, height=350)
       self.text = "FileParsing"
       self.help = '下传文件解析比对工具使用说明'
       self.set_frame()
 
   def showHelp(self):
       textHelp = '''
       使用：
       1. 确认exe同一个目录下有：config.ini 。
       2. 选择支持文件，选择日期，点击查询->显示文件列表。
       3. 选择文件列表的某个文件，点击下载->目录文件下载本地目录，点击解析->保存表数据与文件的对比excel文件。
       4. ftp-126，DB数据库，文件解析等配置项，均写在config.ini文件中，文件不允许汉字。
       5. 文件解析的spliter，指的是分隔符对应的accii码值。
       '''
       messagebox.showinfo(title='使用说明', message=textHelp)
 
   def set_frame(self):
       if not os.path.exists('config.ini'):
           messagebox.showinfo(title='提示', message='当前目录下不存在配置文件config.ini')
 
       config = configparser.ConfigParser()
       config.read('config.ini')
 
       # 数据库连接配置
       DBs = {}
       for db in [k for k in config.sections() if k.startswith('DB')]:
           DBs[db.split('-')[1]] = dict(DATABASE=myconfig(db, 'DATABASE'), HOSTNAME=myconfig(db, 'HOSTNAME'),
                                        PORT=myconfig(db, 'PORT'), PROTOCOL=myconfig(db, 'PROTOCOL'),
                                        UID=myconfig(db, 'UID'), PWD=myconfig(db, 'PWD'))
 
       supportFiles = [k.split('-')[1] for k in config.sections() if k.startswith('FILE')]
       # 解析文件配置，包括对应的数据库，对应的表，文件存放的路径，表对应的主键字段，主键字段表中的顺序，文件中的分隔符
       FILEs = {}
       for file in [k for k in config.sections() if k.startswith('FILE')]:
           FILEs[file.split('-')[1]] = dict(database=myconfig(file, 'database'), table=myconfig(file, 'table'),
                                            path=myconfig(file, 'path'), key=myconfig(file, 'key'),
                                            keyindex=myconfig(file, 'keyindex','isint'),
                                            spliter=myconfig(file, 'spliter','isint'))
       #函数：获取当前日期的前mo个月对应的日期，只变化月份，日份不变
       def myPreMonths(mo, da=0):
           nowdays = datetime.now() - timedelta(days=int(da))
           if nowdays.month - mo <= 0:
               mon = 12 + nowdays.month - mo
           else:
               mon = nowdays.month - mo
           return date(nowdays.year - (nowdays.month <= mo), mon, nowdays.day).strftime('%Y%m%d')
       #获取path路径下符合日期要求的文件列表。ORE7701U的path包含日期，随日期变化，单独处理。
       def myList(tempDict, sftp, mon):
           mon = int(mon)
           tempList = []
           try:
               if tempDict == 'ORE7701U':
                   # 组装的路径文件在远程不存在是，打印出来路径下对应的文件有哪些。不稳定，有失败，待优化。
                   tempPath = '/home/fits/aps/hisData/'
                   threeMonthsAgo = myPreMonths(mon)
                   files = [ff for ff in sftp.listdir(tempPath) if len(ff) == 8 and ff >= threeMonthsAgo]
                   for pa in files:
                       tempPath = tempPath + pa + '/REPSS/'
                       try:
                           temp = [ff for ff in sftp.listdir(tempPath) if ff.startswith('ORE7701U')]
                           if temp != []:
                               sfile = sftp.open(tempPath + temp[0])
                               tempList.append(
                                   tempPath + temp[0] + ' 大小为 %s kB' % str((round(sfile._get_size() / 1024, 2))))
                               sfile.close()
                       except Exception:
                           pass
                       tempPath = '/home/fits/aps/hisData/'
               else:
                   files = sftp.listdir(FILEs[tempDict]['path'])
                   for file in files:
                       if file.startswith(tempDict) and file.split('.')[0][-8:] >= str(myPreMonths(mon)):
                           sfile = sftp.open(FILEs[tempDict]['path'] + file)
                           tempList.append(FILEs[tempDict]['path'] + file + ' 大小为 %s kB' % str(
                               (round(sfile._get_size() / 1024, 2))))
                           sfile.close()
           except Exception:
               pass
           return tempList
 
       sftp = mySftp()
 
       Label(self.frame, text='支持文件列表：').place(x=10, y=15)
       combox = ttk.Combobox(self.frame, values=supportFiles, width=20)
       combox.current(0)
       combox.place(x=100, y=15)
 
       Label(self.frame, text='近x个月的文件列表，共x条：').place(x=10, y=50)
       listvar = StringVar()
       listbox = Listbox(self.frame, listvariable=listvar, selectmod=BROWSE, width=75)
       listbox.place(x=10, y=80)
       #更新Label及listbox文件列表内容
       def li():
           global tempDict, months
           tempDict = combox.get().split('-')[0]
           months = combox2.get()
           temp = myList(tempDict, sftp, months)
           Label(self.frame, text='近%s个月的文件列表，共%d条：' % (months, len(temp))).place(x=10, y=50)
           listvar.set([])
           for v in temp:
               listbox.insert(0, v)
 
       Label(self.frame, text='查询时间：').place(x=300, y=15)
       monlist = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12']
       combox2 = ttk.Combobox(self.frame, values=monlist, width=2)
       combox2.current(2)
       combox2.place(x=370, y=15)
       Label(self.frame, text='个月内').place(x=410, y=15)
       Button(self.frame, text='查询', command=li).place(x=470, y=10)
       #解析文件，button调用
       def anly():
           global desPath
           try:
               desPath = listbox.get(listbox.curselection()).split(' ')[0]
           except Exception:
               messagebox.showwarning(title='警告', message='未选中文件列表的文件')
               return
           tempFile = 'temp'
           try:
               sftp.get(desPath, tempFile)  # 下载文件到本地
               if os.path.getsize(tempFile) <= 0:
                   messagebox.showwarning(title='警告', message=desPath + '文件为空')
                   os.remove(tempFile)
                   return
           except Exception as e:
               messagebox.showwarning(title='警告', message='%s 文件不存在' % desPath)
               return
           # 打开temp文件
           remote_file = open(tempFile, 'r')
           # 新建一个excel，设置字体，边框
           wbk = xlwt.Workbook()  # 新建
           sheet = wbk.add_sheet(desPath.split('/')[-1].split('.')[0])
 
           col = 0
           try:
               for line in remote_file.readlines():  # 读取temp文件的一行
                   # 去除一行前后的回车换行符，根据spliter解析为list
                   data = line.strip('\r\n').split(chr(FILEs[tempDict]['spliter']))
                   # ORED048U需要单独处理，spliter为逗号，但数据中存在 0012,0015,0018 类似的数据，
                   # 这个字段是正数第114和倒数第-27字段，单独处理，重新合并data
                   if tempDict == 'ORED048U':
                       da = data[114:-27]
                       ss = ''
                       for d in da:
                           ss = ss + d.strip('"') + ','
                       data[114] = ss[:-1]
                       data = data[:115] + data[-27:]
                   # 根据主键字段key到对应的table查询对应的keyindex值，得到对应的数据
                   sql = str.format(" select * from %s where %s = '%s'" % (
                       FILEs[tempDict]['table'], FILEs[tempDict]['key'],str(data[FILEs[tempDict]['keyindex']]).strip('"')))
                   result = DBHelper(DBs[FILEs[tempDict]['database']]).queryAction(sql)[0]
                   # print(result)
                   if result:
                       sheet.col(col).width = 4500  # 设置列宽
                       sheet.col(col + 1).width = 4500
                       sheet.write(0, col, '文件数据', styleCommon)
                       sheet.write(0, col + 1, '表数据')
                       for num in range(len(data)):
                           dataTemp = str(data[num]).strip('"')
                           sheet.write(num + 1, col, dataTemp, styleCommon)  # styleCommon加边框
                           if result[num] is None:
                               if dataTemp != '':
                                   sheet.write(num + 1, col + 1, '', styleSpec)  # 不相等数据设置为styleSpec
                           else:
                               if dataTemp != str(result[num]):
                                   sheet.write(num + 1, col + 1, str(result[num]), styleSpec)  # 不相等数据设置为styleSpec
                               else:
                                   sheet.write(num + 1, col + 1, str(result[num]))
                       col = col + 2
                       if col > 255:
                           # print('超过excel的255列')
                           break
           except Exception as e:
               pass
           finally:
               # 关闭文件并删除
               remote_file.close()
               os.remove(tempFile)
           # 保存excel
           xlsName = tempDict + '_' + datetime.now().strftime('%Y%m%d%H%M%S') + '.xls'
           wbk.save(xlsName)
           messagebox.showinfo(title='提示', message=xlsName + ' 文件已保存当前目录')
 
       Button(self.frame, text='解析', command=anly).place(x=320, y=268)
 
       def download():
           try:
               desPath = listbox.get(listbox.curselection()).split(' ')[0]
           except Exception:
               messagebox.showwarning(title='警告', message='未选中文件列表的文件')
               return
           sftp.get(desPath, os.path.join(os.getcwd(), desPath.split('/')[-1]))
           messagebox.showinfo(title='提示', message=desPath.split('/')[-1] + ' 文件已保存当前目录')
 
       Button(self.frame, text='下载', command=download).place(x=220, y=268)
 